package cn.mill.support;

import java.io.InputStream;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import cn.mill.common.Context;
import cn.mill.common.Strategy;
import cn.mill.common.annotation.SPI;
import cn.mill.common.data.DataCommon;
import cn.mill.common.data.Item;
import cn.mill.common.data.ItemArray;
import cn.mill.common.message.Message;
import cn.mill.core.DefaultData;
import cn.mill.core.DefaultMessage;
import cn.mill.core.utils.NormUtil;

@SPI("json")
public class JsonStrategy implements Strategy<String, InputStream> {
	private static Logger logger = LoggerFactory.getLogger(JsonStrategy.class);
	
	@Override
	public Message<String> write(Context invoke, ItemArray itemArray) {
		DefaultMessage<String> message = new DefaultMessage<String>();
		JSONObject dataObject = new JSONObject();
		for (Item i : itemArray.getItems()) {
			if (i.getValue() instanceof ItemArray) {
				JSONObject subObject = new JSONObject();
				ItemArray arry = (ItemArray) i.getValue();
				for (Item item : arry.getItems()) {
					subObject.put(item.getName(), item.getValue());
				}
				dataObject.put(i.getName(), subObject);
			} else {
				dataObject.put(i.getName(), i.getValue());
			}
		}
		message.setDataBlock(dataObject.toJSONString());
		return message;
	}
	
	@Override
	public DataCommon<ItemArray> read(Context invoke, Message<InputStream> message) {
		DefaultData defaultData = new DefaultData();
		if (message != null && message.getDataBlock() != null) {
			ItemArray array = null;
			String text = NormUtil.readStream(message.getDataBlock());
			if (NormUtil.isNotEmpty(text)) {
				logger.debug("text:[" + text + "]");
				if (text.indexOf("[") == 0) {
					array = this.builderJsonArray(JSON.parseArray(text));
				} else {
					JSONObject jsonObject = JSON.parseObject(text);
					array = this.builderJsonObject(jsonObject);
				}
			}
			defaultData.setValue(array);
			defaultData.setFine(true);
		} else {
			defaultData.setFine(false);
		}
		return defaultData;
	}
	
	private ItemArray builderJsonArray(JSONArray array) {
		ItemArray itemArray = new ItemArray(array == null ? 0 : array.size());
		if (array != null && array.size() > 0) {
			for (int i = 0; i < array.size(); i++) {
				Object object = array.get(i);
				if (object instanceof JSONObject) {
					ItemArray iArray = new ItemArray(array.getJSONObject(i).size());
					for (Map.Entry<String, Object> entry : array.getJSONObject(i).entrySet()) {
						iArray.addItem(new Item(null, entry.getKey(), String.class, entry.getValue()));
					}
					itemArray.addItem(new Item(null, "ARRAY", null, iArray));
				} else {
					itemArray.addItem(new Item(null, "ARRAY", null, object.toString()));
				}
			}
		}
		return itemArray;
	}
	
	private ItemArray builderJsonObject(JSONObject jsonObject) {
		ItemArray array = new ItemArray(jsonObject == null ? 0 : jsonObject.size());
		if (jsonObject != null && !jsonObject.isEmpty()) {
			for (Map.Entry<String, Object> entry : jsonObject.entrySet()) {
				if (entry.getValue() instanceof JSONArray) {
					ItemArray itemArray = builderJsonArray((JSONArray) entry.getValue());
					array.addItem(new Item(null, entry.getKey(), null, itemArray));
				} else if (entry.getValue() instanceof JSONObject) {
					array.addItem(new Item(null, entry.getKey(), null, builderJsonObject((JSONObject) entry.getValue())));
				} else {
					array.addItem(new Item(null, entry.getKey(), String.class, entry.getValue()));
				}
			}
		}
		return array;
	}
}
